#include "stdafx.h"

#include "qwindow.h"
#include "qgraphics.h"
#include "qerror.h"



#define GET_X_LPARAM(lp)                        ((int)(short)LOWORD(lp))
#define GET_Y_LPARAM(lp)                        ((int)(short)HIWORD(lp))



bool  QWindow::OnPreRegisterClass( WNDCLASS & wc )
{

    //wcex.cbSize = sizeof(wcex);
    wc.style			= CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; //face restergerea... sau stergerea + redesenarea
    wc.lpfnWndProc		= StaticWindowProcInit;
    wc.cbClsExtra		= 0;
    wc.cbWndExtra		= 0;
    wc.hInstance		= GetModuleHandle( 0 );
    wc.hIcon			= 0;//LoadIcon(nullptr, MAKEINTRESOURCE(IDI_UCOMMANDER));
    wc.hCursor			= ::LoadCursor( nullptr, IDC_ARROW );
    wc.hbrBackground	= ( HBRUSH )( COLOR_WINDOW + 1 );
    wc.lpszMenuName		= nullptr;
    wc.lpszClassName	= _T( "QW" );
    return true;
}
bool QWindow::OnPreCreate( CREATESTRUCT & cs )
{

    cs.style = 0;

    cs.x = CW_USEDEFAULT;
    cs.y = CW_USEDEFAULT;
    cs.cx = 0;
    cs.cy = 0;
    cs.lpCreateParams = this;/*pt a atasa clasa ferestrei */
    return true;

}

void QWindow::SetFont( HFONT hFont, BOOL bRedraw )
{
    ASSERT( ::IsWindow( _window ) );
    ::SendMessage( _window, WM_SETFONT, ( WPARAM )hFont, MAKELPARAM( bRedraw, 0 ) );
}

HFONT QWindow::GetFont() const
{
    ASSERT( ::IsWindow( _window ) );
    return ( HFONT )::SendMessage( _window, WM_GETFONT, 0, 0 );
}

void QWindow::ClientToScreen( QRect & rect ) const
{
    ::ClientToScreen( _window, ( LPPOINT )&rect );
    ::ClientToScreen( _window, ( ( LPPOINT )&rect ) + 1  );
}

void QWindow::ScreenToClient( QRect & rect ) const
{
    ::ScreenToClient( _window, ( LPPOINT )&rect );
    ::ScreenToClient( _window, ( ( LPPOINT )&rect ) + 1 );
}


bool QWindow::CreateBaseWindowEx( DWORD exStyle, LPCTSTR className,
                                  LPCTSTR windowName, DWORD style,
                                  QRect & rect,
                                  QWindow * parentWindow, UINT_PTR idOrHMenu,
                                  HINSTANCE instance, LPVOID createParam )
{
    HWND hwndParent = nullptr;

    if ( parentWindow )
        hwndParent = parentWindow->GetHandle();


    WNDCLASS wc			= {0};
    wc.lpszClassName	= className;
    wc.lpszMenuName		= ( LPCTSTR )idOrHMenu;
    wc.hCursor			= ::LoadCursor( nullptr, IDC_ARROW );
    wc.hbrBackground	= ( HBRUSH )( COLOR_WINDOW + 1 );
    wc.style			= CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;


    if ( !RegisterClass( wc ) )	// Register the window class (if not already registered)
        throw QError( _T( "CBWX" ) );

    _window = ::CreateWindowEx( exStyle, className, windowName,
                                style, rect.left, rect.top, rect.Width(), rect.Height(), hwndParent,
                                ( HMENU )idOrHMenu, instance, createParam );

    return ( _window != nullptr );
}


bool QWindow::CreateBaseWindow( LPCTSTR className,
                                LPCTSTR windowName, DWORD style,
                                QRect & rect,
                                QWindow * parentWindow, int idOrHMenu,
                                HINSTANCE instance, LPVOID createParam )
{
    return CreateBaseWindowEx( 0, className, windowName, style, rect, parentWindow,   idOrHMenu,  instance,   createParam );
}

bool QWindow::Create( QWindow * pParent /* = nullptr */, int id, UINT style )
{
    HWND hWndParent = nullptr;

    if ( pParent )
        hWndParent = pParent->GetHandle();

    try
    {
        // Set the WNDCLASS parameters
        WNDCLASS		wc = { 0 };
        CREATESTRUCT	m_cs = { 0 };


        wc.lpfnWndProc		= StaticWindowProcInit;
        wc.hInstance		= GetModuleHandle( 0 );
        
		wc.hbrBackground	= ( HBRUSH )( COLOR_WINDOW + 1 );
        wc.lpszClassName	= _T( "QW" );


        //asta trebuie mutat in Registerclass
        OnPreRegisterClass( wc );

        if ( wc.lpszClassName )
        {
            RegisterClass( wc );
            m_cs.lpszClass = wc.lpszClassName;
        }



        //modificare
        OnPreCreate( m_cs );




        // Set the window style
        DWORD dwStyle = style;

        if ( m_cs.style )
            dwStyle |=  m_cs.style;

        else
            dwStyle |=  ( ( hWndParent ) ? WS_VISIBLE | WS_CHILD  : WS_OVERLAPPEDWINDOW );


        if ( nullptr == m_cs.hMenu )
            m_cs.hMenu = ( HMENU )id;

        // Create the window
        _window = CreateWindowEx( m_cs.dwExStyle, wc.lpszClassName, m_cs.lpszName, dwStyle, m_cs.x, m_cs.y,
                                  m_cs.cx, m_cs.cy, hWndParent, m_cs.hMenu, GetModuleHandle( 0 ), m_cs.lpCreateParams );

    }
    catch( QError & e )
    {
        e.PrintMessage();
    }

    return true;
}



bool QWindow::RegisterClass( WNDCLASS & wc )
{
    try
    {
        HINSTANCE hinst = GetModuleHandle( 0 );

        if ( 0 == _tcslen( wc.lpszClassName )  || ( _tcslen( wc.lpszClassName ) >  255 )	)
            throw QError( QString ( _T( "RC1 " ) ) + wc.lpszClassName );

        // Check to see if this classname is already registered
        WNDCLASS wcTest = { 0 };

        if ( ::GetClassInfo( hinst , wc.lpszClassName, &wcTest ) )
        {
            wc = wcTest;
            return true;
        }

        // Set defaults
        wc.hInstance	= hinst;
        wc.lpfnWndProc	= QWindow::StaticWindowProcInit;


        // Register the WNDCLASS structure
        if ( !::RegisterClass( &wc ) )
            throw QError( QString( _T( "RC2 " ) ) + wc.lpszClassName );

        return true;
    }
    catch( QError & e )
    {
        e.PrintMessage();
    }

    return false;
}




LRESULT CALLBACK QWindow::StaticWindowProcInit( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    LRESULT lResult = 0;

    if ( WM_NCCREATE == message )
    {
        QWindow * pThis = reinterpret_cast<QWindow *>( ( ( LPCREATESTRUCT )lParam )->lpCreateParams  );
        ::SetWindowLongPtr( hWnd, GWLP_USERDATA, ( LONG_PTR )pThis );

        if ( pThis != nullptr )
            pThis->Attach( hWnd ); //pentru ca create inca nu a returnat

        ::SetWindowLongPtr( hWnd, GWLP_WNDPROC,  ( LONG_PTR ) StaticWindowProc );
        return ::CallWindowProc( StaticWindowProc, hWnd, message, wParam, lParam );
    }

    return ::DefWindowProc( hWnd,   message,   wParam,   lParam );
}


//for my windows only, not for subclassed one
LRESULT CALLBACK QWindow::StaticWindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    LRESULT lResult = 0;

    QWindow * pWindow = reinterpret_cast<QWindow *>( ::GetWindowLongPtr( hWnd, GWLP_USERDATA ) );

    if ( pWindow == nullptr )
        return 0;

    try
    {

        //crash on WM_ACTIVATEAPP
        bool bo = pWindow->OnMessage( message, wParam, lParam, lResult );

        if ( bo )
            return lResult;

        //return   pWindow->DefWindowProc(message, wParam, lParam); //take into account m_oldWndProc
        return   ::DefWindowProc( hWnd, message, wParam, lParam );
    }
    catch
        ( ... )
    {
        QError e;
        e.PrintMessage();
    }

    return lResult;
}





//unicode and nonunicode
LRESULT QWindow::DefWindowProc( UINT uID, WPARAM wParam, LPARAM lParam )
{
    //if (m_oldWndProc)
    //	return ::CallWindowProc(m_oldWndProc, _window, uID,wParam, lParam);

    return ::DefWindowProc( _window, uID, wParam, lParam );
}



//unicode and nonunicode
//bool QWindow::SubclassWindow2( )
//{
//	ASSERT(::IsWindow(_window));
//
//
//	WNDPROC m_oldProc = ( WNDPROC )GetWindowLong(    GWLP_WNDPROC );
//	WNDPROC m_wndProc = ( WNDPROC ) StaticWindowProc;
//
//	// Is the window proc already our  window procedure?
//	if ( m_oldProc && (m_oldProc != m_wndProc) )
//	{
//		// Get the window procedure.
//		m_oldWndProc = m_oldProc;
//
//
//
//		// Call the PreSubclassWindow() override.
//		PreSubclassWindow();
//
//
//		// Subclass the original window
//		// procedure.
//		if ( SetWindowLong(GWLP_WNDPROC, ( LONG_PTR ) StaticWindowProc ))
//		{
//
//			QWindow* pWnd = reinterpret_cast<QWindow*>(this);
//			SetUserDataLong( (LONG_PTR)pWnd );
//			return true;
//		}
//	}
//	return false;
//}



//////////////////////////////////////////////////////////////////////////
//unicode only
//lanturi de subclasare
//trebuie sa iesi din lant inainte de destroy
LRESULT CALLBACK QWindow::SubclassWindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,  UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
{
    //ASSERT(uIdSubclass==0);

    LRESULT lResult = 0;

    if ( dwRefData )
    {
        QWindow * pwin = reinterpret_cast<QWindow *>( dwRefData );
        bool bo = pwin->OnMessage( message, wParam	, lParam, lResult );

        if ( bo )
            return lResult;
    }

    return DefSubclassProc( hWnd, message, wParam, lParam );
}


//Note  All strings passed to the procedure are Unicode strings even if Unicode is not specified as a preprocessor definition.
bool QWindow::SubclassWindow( )
{
    ASSERT( ::IsWindow( _window ) );
    PreSubclassWindow();//functie vida
    return TRUE == SetWindowSubclass( _window, SubclassWindowProc, 0, DWORD_PTR( this ) );
}

bool QWindow::UnSubclassWindow( )
{
    return TRUE == RemoveWindowSubclass( _window, SubclassWindowProc, 0  );
}
//////////////////////////////////////////////////////////////////////////



bool  QWindow::PreTranslateMessage( MSG * pMsg )
{
    return false;
}



// All   windows direct their messages here.
// This function redirects the message
// to the CWnd's WndProc function.
//ONLY FOR POWER USERS
bool QWindow::OnMessage( UINT message, WPARAM wParam, LPARAM lParam, LRESULT & lResult )
{

    lResult = 0;

    // special case for notifies
    if ( message == WM_NOTIFY )
    {
        //bool lr;
        // Handle the frame notifications
        //lr = OnNotifyFrame(wParam, lParam);
        //if (lr) return  lr;


        //lr = OnNotifyReflect(wParam, lParam);
        //if (lr) return  lr;




        // Handle user notifications
        return  OnNotify( wParam, ( LPNMHDR ) lParam, lResult );
    }


    //WM_HOTKEY
    //WM_MEASUREITEM
    //WM_DRAWTEM
    //WM_SETCURSOR
    //WM_GETMINMAXINFO
    //WM_SHOWWINDOW
    //WM_QUERYOPEN
    //WM_ENDSESSION
    //WM_QUERYENDSESSION
    //WM_HSCROLL
    //WM_VSCROLL
    //WM_INITMENU
    //WM_INITMENUPOPUP
    //WM_MENUSELECT
    //WM_SETICON

    switch ( message )
    {


        case WM_DISPLAYCHANGE: //message is sent to all windows when the display resolution has changed
        case WM_PAINT:
            {
                QPaintGraphics dc( this ); //apare PE AICI WM_NCPAINT, WM_ERASEBKGND
                return  OnPaint( &dc );   //a nu se pastra dc
            }

        case WM_ERASEBKGND:
            {
                HDC hdc = ( HDC )wParam;
                QGraphics dc( hdc );
                bool bo =   OnEraseBackground( &dc ); //virtual	;
                dc.Detach();
                return bo;
            }

        case WM_NCPAINT:
            {
                //QWindowGraphics dc(this);
                return OnNcPaint(  wParam, lParam );
            }


        case WM_COMMAND:
            {
                return  OnCommand( wParam,  lParam ); //virtual

            }


        case WM_CREATE: //trimis de CreateWindow si  primit inainte de as se termina CreateWindow
            {
                //log << "------------ QWindow:WM_CREATE - client"<<endl;
                return OnCreateClient(); //virtual
            }

        case WM_NCCREATE: //trimis de CreateWindow si  primit inainte de as se termina CreateWindow
            {
                //log << "------------ QWindow:WM_NCCREATE"<<endl;
                return OnNcCreate(); //virtual	OnNcCreate(LPCREATESTRUCT lpCreateStruct)
            }



        case WM_DESTROY:
            {
                //cineva a apelat DestroyWindow()
                return OnDestroy();
            }

        case WM_NCDESTROY:
            {
                return OnNcDestroy();

            }

        case WM_TIMER:
            {
                return OnTimer( wParam );
            }

        case WM_NCCALCSIZE:
            {
                //log << typeid(*this).name()<< "::WM_NCCALCSIZE"<<endl;
                return    OnNcCalcSize( ( BOOL )wParam, ( NCCALCSIZE_PARAMS * )lParam );
            }


        case WM_NCHITTEST:
            {
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );

                //HTBORDER
                QPoint pt( cx, cy );//screen
                //ScreenToClient( pt ); //function nedd to compute with windowrect

                return OnNcHitTest( pt, lResult );
            }

        case WM_NCMOUSEMOVE:
            {
                //wparam = hit_test
                //lparam = point
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );

                QPoint pt( cx, cy ); //screen coordinates

                return OnNcMouseMove( wParam, pt );
            }


        case WM_GETMINMAXINFO:
			{
				LPMINMAXINFO pmmi = ( LPMINMAXINFO )lParam;
				return OnGetMinMaxInfo(pmmi);
			}

        case WM_SIZE:
            {

                //log <<  typeid(*this).name()<< "::WM_SIZE"<<endl;

                int type = ( int )wParam; //SIZE_MINIMIZED
                int cx = LOWORD( lParam );
                int cy = HIWORD( lParam );

                return  OnSize( type, cx, cy ); //virtual;
            }

        case WM_WINDOWPOSCHANGING:
            {
                return OnPosChanging( ( WINDOWPOS * ) lParam );
            }

        case WM_WINDOWPOSCHANGED:
            {
                return OnPosChanged( ( WINDOWPOS * ) lParam );
            }

        case WM_MOUSEMOVE:
            {
                UINT flags = ( int )wParam; //MK_CONTROL | MK_SHIFT
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );

                //If an application processes this message, it should return zero.
                return  OnMouseMove( flags, QPoint( cx, cy ) );
            }


        case WM_LBUTTONDOWN:
            {
                UINT flags = ( int )wParam; //MK_CONTROL | MK_SHIFT
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );


                return OnLButtonDown( flags, QPoint( cx, cy ) );
            }

        case WM_LBUTTONUP:
            {

                UINT flags = ( int )wParam; //MK_CONTROL | MK_SHIFT
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );

                return OnLButtonUp( flags, QPoint( cx, cy ) );

            }

        case WM_RBUTTONDOWN:
            {
                UINT flags = ( int )wParam; //MK_CONTROL | MK_SHIFT
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );

                return OnRButtonDown( flags, QPoint( cx, cy ) );

            }


        case WM_RBUTTONUP:
            {

                UINT flags = ( int )wParam; //MK_CONTROL | MK_SHIFT
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );

                return OnRButtonUp( flags,  QPoint( cx, cy ) );
            }


        case WM_LBUTTONDBLCLK:
            {

                UINT flags = ( int )wParam; //MK_CONTROL | MK_SHIFT
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );

                return OnLButtonDblClk( flags, QPoint( cx, cy ) );
            }

        case WM_RBUTTONDBLCLK:
            {

                UINT flags = ( int )wParam; //MK_CONTROL | MK_SHIFT
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );

                return OnRButtonDblClk( flags, QPoint( cx, cy ) );
            }

        case WM_MBUTTONDOWN:
            {
                UINT flags = ( int )wParam; //MK_CONTROL | MK_SHIFT
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );
                return OnMButtonDown( flags, QPoint( cx, cy ) );

            }

        case WM_MBUTTONUP:
            {
                UINT flags = ( int )wParam; //MK_CONTROL | MK_SHIFT
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );
                return OnMButtonUp( flags, QPoint( cx, cy ) );

            }

        case WM_MBUTTONDBLCLK:
            {
                UINT flags = ( int )wParam; //MK_CONTROL | MK_SHIFT
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );
                return OnMButtonDblClk( flags, QPoint( cx, cy ) );

            }

        case WM_MOUSEWHEEL:
            {

                UINT flags = LOWORD( wParam );
                int delta = ( short ) HIWORD( wParam ); //in unitati * 120  distance, negative apropiere  , pozitiv departare

                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );

                return  OnMouseWheel( flags, delta,  QPoint( cx, cy ) );

            }

        case WM_MOUSEHWHEEL:
            {

                //fwKeys = GET_KEYSTATE_WPARAM(wParam);
                //zDelta = GET_WHEEL_DELTA_WPARAM(wParam);



                UINT flags = LOWORD( wParam );
                int delta = ( short ) HIWORD( wParam ); //in unitati * 120  distance, negative apropiere  , pozitiv departare

                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );

                return  OnMouseHWheel( flags, delta,  QPoint( cx, cy ) );

            }

        case WM_MOUSEHOVER:
            {
                UINT flags = ( int )wParam; //MK_CONTROL | MK_SHIFT  MK_LBUTTON MK_MBUTTON MK_RBUTTON MK_XBUTTON1 MK_XBUTTON2
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );

                ///If an application processes this message, it should return zero.
                return OnMouseHover( flags,  QPoint( cx, cy ) );
            }

        case WM_MOUSELEAVE:
            {
                ///If an application processes this message, it should return zero.
                return OnMouseLeave();

            }

        case WM_NCMOUSEHOVER:
            {
                UINT flags = ( int )wParam; //MK_CONTROL | MK_SHIFT ...
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );
                return   OnNcMouseHover(  flags,  QPoint( cx, cy ) );

            }

        case WM_NCMOUSELEAVE:
            {
                return OnNcMouseLeave();
            }

        case WM_NCLBUTTONDOWN:
            {
                UINT flags = ( int )wParam; //MK_CONTROL | MK_SHIFT
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );


                return OnNcLButtonDown( flags, QPoint( cx, cy ) );
            }

        case WM_NCLBUTTONUP:
            {

                UINT flags = ( int )wParam; //MK_CONTROL | MK_SHIFT
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );

                return OnNcLButtonUp( flags, QPoint( cx, cy ) );

            }

        case WM_NCRBUTTONDOWN:
            {
                UINT flags = ( int )wParam; //MK_CONTROL | MK_SHIFT
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );

                return OnNcRButtonDown( flags, QPoint( cx, cy ) );

            }


        case WM_NCRBUTTONUP:
            {

                UINT flags = ( int )wParam; //MK_CONTROL | MK_SHIFT
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );

                return OnNcRButtonUp( flags,  QPoint( cx, cy ) );
            }


        case WM_NCLBUTTONDBLCLK:
            {

                UINT flags = ( int )wParam; //MK_CONTROL | MK_SHIFT
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );

                return OnNcLButtonDblClk( flags, QPoint( cx, cy ) );
            }

        case WM_NCRBUTTONDBLCLK:
            {

                UINT flags = ( int )wParam; //MK_CONTROL | MK_SHIFT
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );

                return OnNcRButtonDblClk( flags, QPoint( cx, cy ) );
            }

        case WM_NCMBUTTONDOWN:
            {
                UINT flags = ( int )wParam; //MK_CONTROL | MK_SHIFT
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );
                return OnNcMButtonDown( flags, QPoint( cx, cy ) );

            }

        case WM_NCMBUTTONUP:
            {
                UINT flags = ( int )wParam; //MK_CONTROL | MK_SHIFT
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );
                return OnNcMButtonUp( flags, QPoint( cx, cy ) );

            }

        case WM_NCMBUTTONDBLCLK:
            {
                UINT flags = ( int )wParam; //MK_CONTROL | MK_SHIFT
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );
                return OnNcMButtonDblClk( flags, QPoint( cx, cy ) );

            }


        case WM_CONTEXTMENU:
            {
                //UINT flags = (int)wParam;  //MK_CONTROL | MK_SHIFT
                int cx = GET_X_LPARAM( lParam );
                int cy = GET_Y_LPARAM( lParam );
                return OnContextMenu( HWND( wParam ), QPoint( cx, cy ) );
            }

        case WM_CAPTURECHANGED: //window is loosing mouse capture forced, do not call setcapture in this function
            {
                return OnCaptureChanged();
            }

        case WM_ACTIVATEAPP:
            {
                //If an application processes this message, it should return zero.
                return  OnActivateApp( toBool( wParam ), ( UINT_PTR )lParam );
            }

        case WM_ACTIVATE:
            {
                ///If the window is being activated and is not minimized, the DefWindowProc function sets the keyboard focus to the window.
                ///If the window is activated by a mouse click, it also receives a WM_MOUSEACTIVATE message.
                HWND hwnd = ( HWND ) lParam;
                UINT active = LOWORD( wParam ); //valoare returnata de la nc_hittest precedent
                UINT minMax = HIWORD( wParam );

                //If an application processes this message, it should return zero.
                return  OnActivate( hwnd,  active,  minMax ); //implicit
            }

        case WM_MOUSEACTIVATE:
            {
                HWND hwnd = ( HWND ) wParam;
                UINT nHitTest = LOWORD( lParam ); //valoare returnata de la nc_hittest precedent
                UINT message = HIWORD( lParam );


                //se trimite intai WM_ACTIVATE
                //LRESULT & lResult
                return OnMouseActivate( hwnd, nHitTest, message, lResult );

            }

        case WM_NCACTIVATE:
            {

                //When the wParam parameter is FALSE, an application should return TRUE to indicate that the system should proceed with the default processing,
                //or it should return FALSE to prevent the change. When wParam is TRUE, the return value is ignored.

                return OnNcActivate( toBool( wParam ), lResult );
            }


        case WM_DRAWCLIPBOARD:
            {
                return OnDrawClipboard();
            }

        case WM_CHANGECBCHAIN://clipboard
            {
                return OnChangeCbChain( ( HWND )wParam, ( HWND )lParam );
            }

        case WM_KEYDOWN:
            {
                return OnKeyDown( ( UINT )wParam, ( UINT )( lParam & 0xffff ), ( UINT )lParam );
            }

        case WM_KEYUP:
            {
                return OnKeyUp( ( UINT )wParam, ( UINT )( lParam & 0xffff ), ( UINT )lParam );
            }

        case WM_CHAR: //Send by TranslateMessage(). The WM_CHAR message uses Unicode Transformation Format (UTF)-16.
            {

                return OnChar( ( UINT )wParam, ( UINT )( lParam & 0xffff ), ( UINT )lParam );
            }


        case WM_SYSCOMMAND:
            {
                return OnSysCommand( wParam & 0xfff0, lParam );
            }

        case WM_SYSKEYDOWN:
            {
                //::Beep(400,50);
                return   false; //OnKeyDown((UINT)wParam, (UINT)(lParam & 0xffff), (UINT)lParam);
            }

        case WM_SYSKEYUP:
            {
                //::Beep(400,50);
                return   false;//OnKeyUp((UINT)wParam, (UINT)(lParam& 0xffff), (UINT)lParam);
            }



            //added by Costel
        case WM_HOTKEY:
            {

                return   OnHotKey( ( UINT )wParam,  LOWORD( lParam ),  HIWORD( lParam ) );

            }

        case WM_SYSCHAR:
            {
                //// For Alt+Enter Beep disabling
                //UINT scanCode = (UINT)(lParam >> 16) & 0xFF;
                //UINT virtualKey = MapVirtualKey(scanCode, 1);



                //::Beep(400,50);
                return  OnSysChar( ( UINT )wParam, ( UINT )( lParam & 0xffff ), ( UINT )lParam );
            }



        case WM_MOVE:
            {
                int xPos = ( int )( short ) LOWORD( lParam ); // horizontal position
                int yPos = ( int )( short ) HIWORD( lParam ); // vertical position

                return OnMove( xPos, yPos );
            }

        case WM_MOVING:
            {
                //Pointer to a RECT structure with the current position of the window, in screen coordinates
                return OnMoving( ( QRect * )lParam );
            }


        case WM_SETFOCUS:
            {
                return OnSetFocus( ( HWND ) wParam ); //mergem pe implicit
            }

        case WM_KILLFOCUS:
            {
                return OnKillFocus( ( HWND ) wParam ); //mergem pe implicit
            }

        case WM_SETCURSOR:
            {

                //HWND  h = wParam;
                UINT hit = LOWORD( lParam );
                UINT msg = HIWORD( lParam );

                return OnSetCursor(   hit,   msg  );
            }

        case WM_CLOSE:
            {
                return  !OnClose();//aici cred ca tre sa fie pe dos   true = inchide app
                //si trimite un WM_DESTROY
            }

        case WM_DROPFILES:
            {

                return OnDropFiles( ( HDROP )wParam );
            }

        case WM_HSCROLL:
            {
                int code = LOWORD( wParam );
                int pos  = HIWORD( wParam ); //if low-order word is SB_THUMBPOSITION or SB_THUMBTRACK
                //wParam = handle to scrollbar or null

                return OnHScroll( code, pos );
            }

        case WM_VSCROLL:
            {
                int code = LOWORD( wParam );
                int pos = HIWORD( wParam ); //if low-order word is SB_THUMBPOSITION or SB_THUMBTRACK
                //wParam = handle to scrollbar or null

                return OnVScroll( code, pos );
            }

        case WM_SYSCOLORCHANGE:
            {
                return OnSysColorChange();
            }

        case WM_GETDLGCODE:
            {
                return OnGetDlgCode();
            }

        case WM_PARENTNOTIFY:
            {
                //LRESULT lr = 0;//MessageReflect( uMsg, wParam, lParam);
                //if (lr)
                /*
                lowword of wparam is

                WM_CREATE
                Identifier of the child window.
                WM_DESTROY
                Identifier of the child window.
                WM_LBUTTONDOWN
                Undefined.
                WM_MBUTTONDOWN
                Undefined.
                WM_RBUTTONDOWN
                Undefined.
                WM_XBUTTONDOWN

                */
                //sent to all ancestors includind top-level windows
                return OnParentNotify( LOWORD( wParam ), lParam  );
            }

        case WM_THEMECHANGED:
            {
                return OnThemeChanged();
            }

        case WM_CTLCOLORBTN:
            {
                return false;
            }

        case WM_CTLCOLOREDIT: // nu pentru richedit
            {

                return OnCtlColorEdit();
            }

            //case WM_CTLCOLORDLG: primeste doar dialogul
        case WM_CTLCOLORLISTBOX:
        case WM_CTLCOLORSCROLLBAR:


            //si pentru edit read-only
        case WM_CTLCOLORSTATIC://primeste parintele
            {
                //cere setarea culorilor in dc inainte de desenare
                return false;
            }

        case WM_DRAWITEM:
        case WM_MEASUREITEM:
        case WM_DELETEITEM:
        case WM_COMPAREITEM:
        case WM_CHARTOITEM:
        case WM_VKEYTOITEM:



        case WM_DEVICECHANGE:
            {
                //semnaleaza schimbare de diskuri
                return OnDeviceChange( wParam, lParam );
            }


			///close windows session?
        case WM_QUERYENDSESSION:
            {
                //lParam is:
                //ENDSESSION_CLOSEAPP The application is using a file that must be replaced, the system is being serviced, or system resources are exhausted. For more information, see Guidelines for Applications.
                //ENDSESSION_CRITICAL The application is forced to shut down.
                //ENDSESSION_LOGOFF

                lResult =  TRUE; //terminate
                return true;
            }

        case WM_ENDSESSION:
            {
                //save all data here and return zero/ or false for default
                lResult = 0;
                //return true;
                return false;
            }

#if (WINVER >=_WIN32_WINNT_WIN7)

        case WM_DWMCOMPOSITIONCHANGED:
            {
                return  OnCompositionChanged();
            }

        case WM_TOUCH: //for this call RegisterTouchWindow first
            {
                //LO number of touch points
                UINT nr = LOWORD( wParam );
                //reserved HIWORD(wParam);
                HTOUCHINPUT  ht = ( HTOUCHINPUT )lParam;
                return  OnTouch( ht, nr );
            }

        case WM_GESTURENOTIFY:
            {
                return OnGestureNotify( );
            }

        case WM_GESTURE://automathical
            {
                // Insert handler code here to interpret the gesture.
                return  OnGesture( ( HGESTUREINFO )  lParam   );
            }

#endif


    }//switch

    if ( message >= WM_USER )
        return	OnUserMessage( message, wParam, lParam );

    return false;
}

bool  QWindow::OnCtlColorEdit()
{
    return false;
}

bool QWindow::OnThemeChanged()
{
    return false;
}

bool QWindow::OnCommand( WPARAM wParam, LPARAM lParam )
{
    return false;
}

bool QWindow::OnSysCommand( UINT id, LPARAM lParam )
{
    return false;
}

bool QWindow::OnDeviceChange( WPARAM nEventType, LPARAM dwData )
{
    return false;
}

bool QWindow::OnUserMessage( UINT msg, WPARAM  wparam, LPARAM lParam )
{
    return false;
}

bool QWindow::OnSetFocus( HWND hwnd )
{
    return false; //zero if it processes message
}

bool QWindow::OnKillFocus( HWND hwnd )
{
    return false;
}

bool QWindow::OnSetCursor( UINT nHitTest, UINT message )
{
    //parent gets this message first
    return false;//continua retrimiterea
}

bool QWindow::OnSysColorChange()
{
    return false;
}

bool QWindow::OnGetDlgCode( void )
{
    return false;
}

bool QWindow::OnTimer( UINT_PTR id )
{
    return false;
}

bool QWindow::OnCreateClient( void )
{
    return true;
}

bool QWindow::OnNcCreate( void )
{
    return false; //for default proc call
}

bool QWindow::OnSize( int type, int cx, int cy )
{
    ASSERT( _window );
    //MoveWindow(0,0,cx ,cy);/nu se pune in onsize deoarece arunca un mesaj WM_SIZE
    return false;
}

bool QWindow::OnGetMinMaxInfo(LPMINMAXINFO)
{
    ASSERT( _window );
    //MoveWindow(0,0,cx ,cy);/nu se pune in onsize deoarece arunca un mesaj WM_SIZE
    return false;
}

bool QWindow::OnPosChanging( WINDOWPOS * )
{
    return false;
}

bool QWindow::OnPosChanged( WINDOWPOS * )
{
    return false;
}

bool QWindow::OnDropFiles( HDROP file )
{
    return false;
}

bool QWindow::OnDestroy( void )
{
    return false;
}

bool QWindow::OnNcDestroy( void )
{
    return false;
}

bool QWindow::OnMove( int xpos, int ypos )
{
    return false;
}

bool QWindow::OnMoving( QRect * pRect )
{
    return false;
}

bool  QWindow::OnPaint( QGraphics * pdc )
{
    return false;//sa deseneze implicit
}

bool QWindow::OnNcPaint( WPARAM wParam, LPARAM lParam  )
{
    return false; //sa deseneze implicit
}

bool QWindow::OnNcCalcSize( WPARAM indicate, NCCALCSIZE_PARAMS * lParam )
{

    //if indicate ==true lParam is  NCCALCSIZE_PARAMS*
    //if indicate ==false lParam is RECT*

    ///If the wParam parameter is FALSE, the application should return zero.
    ///If wParam is TRUE, the application should return zero or a combination of the following values: WVR_ALIGNTOP  WVR_ALIGNLEFT WVR_ALIGNBOTTOM
    ///If wParam is TRUE and an application returns zero, the old client area is preserved and is aligned with the upper-left corner of the new client area.

    return false; ///sa deseneze implicit
}

bool QWindow::OnNcHitTest( QPoint & pt, LRESULT & lr )
{
    return false;
}
/// FINAL
bool QWindow::OnEraseBackground( QGraphics * pdc )
{

    //0=ocupa-te tu
    //1=m-am ocupat eu
    return false;
}

bool  QWindow::Destroy()
{
    if ( _window == nullptr )
        return true;

    ::DestroyWindow( _window );
    _window = nullptr;
    return true;
}

bool QWindow::OnClose( void )
{
    return true; //adica se poate inchide
}

bool QWindow::OnContextMenu( HWND h, QPoint & point )
{
    return false;
}

bool  QWindow::OnLButtonDown( UINT flags, QPoint & point )
{
    return false;
}

bool QWindow::OnLButtonUp( UINT flags, QPoint & point )
{
    return false;
}
bool QWindow::OnLButtonDblClk( UINT flags, QPoint & point )
{
    return false;
}

bool QWindow::OnRButtonDown( UINT flags, QPoint & point )
{
    return false;
}

bool QWindow::OnRButtonUp( UINT flags, QPoint & point )
{
    return false;
}
bool QWindow::OnRButtonDblClk( UINT flags, QPoint & point )
{
    return false;
}

bool  QWindow::OnNcLButtonDown( UINT nHitTest, QPoint & point )
{
    return false;
}

bool QWindow::OnNcLButtonUp( UINT nHitTest, QPoint & point )
{
    return false;
}
bool QWindow::OnNcLButtonDblClk( UINT nHitTest, QPoint & point )
{
    return false;
}

bool QWindow::OnNcRButtonDown( UINT nHitTest, QPoint & point )
{
    return false;
}

bool QWindow::OnNcRButtonUp( UINT nHitTest, QPoint & point )
{
    return false;
}
bool QWindow::OnNcRButtonDblClk( UINT nHitTest, QPoint & point )
{
    return false;
}

bool QWindow::OnNcMButtonDown( UINT nHitTest, QPoint & point )
{
    return false;
}

bool QWindow::OnNcMButtonUp( UINT nHitTest, QPoint & point )
{
    return false;
}
bool QWindow::OnNcMButtonDblClk( UINT nHitTest, QPoint & point )
{
    return false;
}
bool QWindow::OnNcMouseHover( UINT nHitTest, QPoint & point )
{
    return false;
}

bool QWindow::OnNcMouseLeave()
{
    return false;
}

bool QWindow::OnNcMouseMove( UINT nHitTest, QPoint & pt )
{
    return false;
}

bool QWindow::OnMButtonDown( UINT flags, QPoint & point )
{
    return false;
}

bool QWindow::OnMButtonUp( UINT flags, QPoint & point )
{
    return false;
}
bool QWindow::OnMButtonDblClk( UINT flags, QPoint & point )
{
    return false;
}


bool QWindow::OnMouseMove( UINT flags, QPoint & point )
{
    return false;
}

bool QWindow::OnMouseHover( UINT nFlags, QPoint & point )
{
    return false;
}

bool QWindow:: OnMouseLeave()
{
    return false;
}


bool QWindow::OnCaptureChanged()
{
    return false;
}

bool QWindow::OnActivateApp( bool active, UINT_PTR threadID )
{
    ///If an application processes this message, it should return zero.

    return false;
}

bool QWindow::OnActivate( HWND hwnd, UINT active, UINT minMax )
{
    //SetFocus(); //la activare cu mausul trimite WM_ACTIVATE
    return false;
}
bool QWindow::OnMouseActivate( HWND hwnd, UINT nHitTest, UINT message, LRESULT & lResult )
{

    // The default implementation passes this message to the parent window before any processing occurs.
    // If the parent window returns TRUE, processing is halted.
    // For a description of the individual hit-test area codes, see the OnNcHitTest member function

    //SetFocus(); //la activare cu mausul trimite WM_ACTIVATE
    lResult = MA_ACTIVATE;
    return false;//MA_ACTIVATE;
}
bool QWindow::OnNcActivate( bool active, LRESULT & lr )
{
    //Indicates when a title bar or icon needs to be changed to indicate an active or inactive state.
    //If an active title bar or icon is to be drawn, the wParam parameter is TRUE.
    //If an inactive title bar or icon is to be drawn, wParam is FALSE.

    //When the wParam parameter is FALSE, an application should return TRUE to indicate that the system
    //should proceed with the default processing, or it should return FALSE to prevent the change.
    //When wParam is TRUE, the return value is ignored.


    //When the wParam parameter is FALSE, an application should return TRUE to indicate that the system should proceed with the default processing,
    //or it should return FALSE to prevent the change. When wParam is TRUE, the return value is ignored.


    // se cere desenarea unei ferestre inactive (active ==false), se raspunde cu TRUE pt a permite dezactivarea
    // dar asta doar daca o tratez eu, daca tot dau return false, totul merge pe default
    if ( !active )
        lr = TRUE; //util daca urmeaza return true

    return false;
}

bool QWindow::OnChar( UINT nChar, UINT nRepCnt, UINT nFlags )
{
    return false;
}
bool QWindow::OnSysChar( UINT nChar, UINT nRepCnt, UINT nFlags )
{
    return false;
}
bool QWindow::OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags )
{
    return false;
}
bool QWindow::OnKeyUp( UINT nChar, UINT nRepCnt, UINT nFlags )
{
    return false;
}
bool  QWindow::OnVScroll( UINT code, UINT pos )
{
    return false;
}
bool  QWindow::OnHScroll( UINT code, UINT pos )
{
    return false;
}

bool  QWindow::OnMouseWheel( UINT flags, int delta,  QPoint & p )
{
    return false;
}
bool  QWindow::OnMouseHWheel( UINT flags, int delta,  QPoint & p )
{
    return false;
}
bool QWindow::GetText( QString & s )const
{
    ASSERT( ::IsWindow( _window ) ); // Must be valid.
    int len = ::GetWindowTextLength( _window );

    if ( len == 0 )
    {
        s.Empty();
        return true;
    }

    len ++; //for terminator

    // Get the window text.
    return 0 != ::GetWindowText( _window, s.GetBuffer( len ) , len   );
}


bool QWindow::OnDrawClipboard()
{
    return false;
}
bool QWindow::OnChangeCbChain( HWND hWndRemove , HWND hWndAfter )
{
    return false;
}

//bool QWindow::OnParentNotify(UINT msg, LPARAM lparam)
//{
//	return false;
//}

// Modify the window style.
void QWindow::ModifyStyle( DWORD dwRemove, DWORD dwAdd, DWORD dwFlags /* = 0 */ )
{
    ASSERT( _window ); // Must be valid.

    // First we get the current window style.
    DWORD dwStyle = ( DWORD )::GetWindowLongPtr( _window, GWL_STYLE );

    // Change bits.
    dwStyle &= ~dwRemove;
    dwStyle |= dwAdd;

    // Change the style.
    ::SetWindowLongPtr( _window, GWL_STYLE, ( LONG_PTR )( dwStyle | dwFlags ) );
}

// Modify the extended window style.
void QWindow::ModifyExStyle( DWORD dwRemove, DWORD dwAdd, DWORD dwFlags /* = 0 */ )
{
    ASSERT( _window ); // Must be valid.

    // First we get the current window extended style.
    DWORD dwExStyle = ( DWORD )::GetWindowLongPtr( _window, GWL_EXSTYLE );

    // Change bits.
    dwExStyle &= ~dwRemove;
    dwExStyle |= dwAdd;

    // Change the extended style.
    SetWindowLong( GWL_EXSTYLE, ( LONG_PTR )( dwExStyle | dwFlags ) );
}





void QWindow::CenterWindow2( HWND hWndCenter )
{
    ASSERT( ::IsWindow( _window )  );

    // determine owner window to center against
    DWORD dwStyle = GetStyle();

    if ( hWndCenter == nullptr )
    {
        if ( dwStyle & WS_CHILD )
            hWndCenter = ::GetParent( _window );

        else
            hWndCenter = ::GetWindow( _window, GW_OWNER );
    }

    // get coordinates of the window relative to its parent
    RECT rcDlg;
    ::GetWindowRect( _window, &rcDlg );
    RECT rcArea;
    RECT rcCenter;
    HWND hWndParent;

    if ( !( dwStyle & WS_CHILD ) )
    {
        // don't center against invisible or minimized windows
        if ( hWndCenter != nullptr )
        {
            DWORD dwStyleCenter = ::GetWindowLong( hWndCenter, GWL_STYLE );

            if ( !( dwStyleCenter & WS_VISIBLE ) || ( dwStyleCenter & WS_MINIMIZE ) )
                hWndCenter = nullptr;
        }

        // center within screen coordinates

        HMONITOR hMonitor = nullptr;

        if ( hWndCenter != nullptr )
        {
            hMonitor = ::MonitorFromWindow( hWndCenter, MONITOR_DEFAULTTONEAREST );
        }

        else
        {
            hMonitor = ::MonitorFromWindow( _window, MONITOR_DEFAULTTONEAREST );
        }

        ASSERT( hMonitor );

        MONITORINFO minfo;
        minfo.cbSize = sizeof( MONITORINFO );
        BOOL bResult = ::GetMonitorInfo( hMonitor, &minfo );

        ASSERT( bResult );

        if ( !bResult )
            return;



        rcArea = minfo.rcWork;


        if ( hWndCenter == nullptr )
            rcCenter = rcArea;

        else
            ::GetWindowRect( hWndCenter, &rcCenter );
    }

    else
    {
        // center within parent client coordinates
        hWndParent = ::GetParent( _window );
        ASSERT( ::IsWindow( hWndParent ) );

        ::GetClientRect( hWndParent, &rcArea );
        ASSERT( ::IsWindow( hWndCenter ) );
        ::GetClientRect( hWndCenter, &rcCenter );
        ::MapWindowPoints( hWndCenter, hWndParent, ( POINT * )&rcCenter, 2 );
    }

    int DlgWidth = rcDlg.right - rcDlg.left;
    int DlgHeight = rcDlg.bottom - rcDlg.top;

    // find dialog's upper left based on rcCenter
    int xLeft = ( rcCenter.left + rcCenter.right ) / 2 - DlgWidth / 2;
    int yTop = ( rcCenter.top + rcCenter.bottom ) / 2 - DlgHeight / 2;

    // if the dialog is outside the screen, move it inside
    if ( xLeft + DlgWidth > rcArea.right )
        xLeft = rcArea.right - DlgWidth;

    if ( xLeft < rcArea.left )
        xLeft = rcArea.left;

    if ( yTop + DlgHeight > rcArea.bottom )
        yTop = rcArea.bottom - DlgHeight;

    if ( yTop < rcArea.top )
        yTop = rcArea.top;

    // map screen coordinates to child coordinates


    SetWindowPos( nullptr, xLeft, yTop, -1, -1,
                  SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
}


void QWindow::CenterWindow( QWindow * pWndToCenterOn )
{
    // Get the client rectangle of the window on which we want to center
    // Make sure the pointer is not nullptr first

    //RECT rc;
    QRect rectToCenterOn;

    if ( pWndToCenterOn == nullptr )
    {

        ::GetWindowRect( ::GetDesktopWindow(), rectToCenterOn );
        //::GetWindowRect( ::GetDesktopWindow(), &rc );
    }

    else
    {
        rectToCenterOn = pWndToCenterOn->GetWindowRect();
    }

    // Get this window's area
    QRect rectSubDialog = GetWindowRect();

    // Now rectWndToCenterOn contains the screen rectangle of the window
    // pointed to by pWndToCenterOn.  Next, we apply the same centering
    // algorithm as does CenterWindow()

    // find the upper left of where we should center to

    int xLeft = ( rectToCenterOn.Width()   -   rectSubDialog.Width() ) / 2;

    int yTop = ( rectToCenterOn.Height() - rectSubDialog.Height() ) / 2;

    // Move the window to the correct coordinates with SetWindowPos()
    SetWindowPos( nullptr, xLeft, yTop, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
}



//call RegisterTouchWindow
#if (WINVER >= _WIN32_WINNT_WIN7)

bool  QWindow::OnCompositionChanged()
{
    return false;
}

bool QWindow::OnTouch( HTOUCHINPUT ht, UINT nr )
{
    return false;
}
bool QWindow::OnGestureNotify( )
{

    //GESTURECONFIG gc = {0,GC_ALLGESTURES,0};
    //BOOL bResult = SetGestureConfig(_window,0,1,&gc,sizeof(GESTURECONFIG));

    //if(!bResult)
    //{
    //	// an error
    //	return false; //to call defaultwndproc
    //}
    return true;
}



bool  QWindow::OnGesture( HGESTUREINFO  lParam  )
{

    return false;
}


#endif

bool  QWindow::OnHotKey( UINT nHotKeyId, UINT nKey1, 	UINT nKey2 )
{
    return false;
}




/*
{

		case GID_PAN:

                    si.nPos -= (gi.ptsLocation.y - lastY) / scale;

                    si.fMask = SIF_POS;
                    SetScrollInfo (hWnd, SB_VERT, &si, TRUE);
                    GetScrollInfo (hWnd, SB_VERT, &si);

                    yOverpan -= lastY - gi.ptsLocation.y;
                    lastY = gi.ptsLocation.y;

                    if (gi.dwFlags & GF_BEGIN){
                        BeginPanningFeedback(hWnd);
                        yOverpan = 0;
                    } else if (gi.dwFlags & GF_END) {
                        EndPanningFeedback(hWnd, TRUE);
                        yOverpan = 0;
                    }

                    if (si.nPos == si.nMin){
                        // we reached the top, pan upwards in y direction
                        UpdatePanningFeedback(hWnd, 0, yOverpan, gi.dwFlags & GF_INERTIA);
                    }else if (si.nPos >= (si.nMax - si.nPage)){
                        // we reached the bottom, pan downwards in y direction
                        UpdatePanningFeedback(hWnd, 0, yOverpan, gi.dwFlags & GF_INERTIA);
                    }
                    ScrollWindow(hWnd, 0, yChar * (yPos - si.nPos), nullptr, nullptr);
                    UpdateWindow (hWnd);

                    return DefWindowProc(hWnd, message, lParam, wParam);

}

BOOL CenterWindow(HWND hWndCenter = nullptr) throw()
{
		ATLASSERT(::IsWindow(m_hWnd));

		// determine owner window to center against
		DWORD dwStyle = GetStyle();
		if(hWndCenter == nullptr)
		{
			if(dwStyle & WS_CHILD)
				hWndCenter = ::GetParent(m_hWnd);
			else
				hWndCenter = ::GetWindow(m_hWnd, GW_OWNER);
		}

		// get coordinates of the window relative to its parent
		RECT rcDlg;
		::GetWindowRect(m_hWnd, &rcDlg);
		RECT rcArea;
		RECT rcCenter;
		HWND hWndParent;
		if(!(dwStyle & WS_CHILD))
		{
			// don't center against invisible or minimized windows
			if(hWndCenter != nullptr)
			{
				DWORD dwStyleCenter = ::GetWindowLong(hWndCenter, GWL_STYLE);
				if(!(dwStyleCenter & WS_VISIBLE) || (dwStyleCenter & WS_MINIMIZE))
					hWndCenter = nullptr;
			}

			// center within screen coordinates
#if WINVER < 0x0500
			::SystemParametersInfo(SPI_GETWORKAREA, nullptr, &rcArea, nullptr);
#else
			HMONITOR hMonitor = nullptr;
			if(hWndCenter != nullptr)
			{
				hMonitor = ::MonitorFromWindow(hWndCenter, MONITOR_DEFAULTTONEAREST);
			}
			else
			{
				hMonitor = ::MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST);
			}
			ATLENSURE_RETURN_VAL(hMonitor != nullptr, FALSE);

			MONITORINFO minfo;
			minfo.cbSize = sizeof(MONITORINFO);
			BOOL bResult = ::GetMonitorInfo(hMonitor, &minfo);
			ATLENSURE_RETURN_VAL(bResult, FALSE);

			rcArea = minfo.rcWork;
#endif
			if(hWndCenter == nullptr)
				rcCenter = rcArea;
			else
				::GetWindowRect(hWndCenter, &rcCenter);
		}
		else
		{
			// center within parent client coordinates
			hWndParent = ::GetParent(m_hWnd);
			ATLASSERT(::IsWindow(hWndParent));

			::GetClientRect(hWndParent, &rcArea);
			ATLASSERT(::IsWindow(hWndCenter));
			::GetClientRect(hWndCenter, &rcCenter);
			::MapWindowPoints(hWndCenter, hWndParent, (POINT*)&rcCenter, 2);
		}

		int DlgWidth = rcDlg.right - rcDlg.left;
		int DlgHeight = rcDlg.bottom - rcDlg.top;

		// find dialog's upper left based on rcCenter
		int xLeft = (rcCenter.left + rcCenter.right) / 2 - DlgWidth / 2;
		int yTop = (rcCenter.top + rcCenter.bottom) / 2 - DlgHeight / 2;

		// if the dialog is outside the screen, move it inside
		if(xLeft + DlgWidth > rcArea.right)
			xLeft = rcArea.right - DlgWidth;
		if(xLeft < rcArea.left)
			xLeft = rcArea.left;

		if(yTop + DlgHeight > rcArea.bottom)
			yTop = rcArea.bottom - DlgHeight;
		if(yTop < rcArea.top)
			yTop = rcArea.top;

		// map screen coordinates to child coordinates
		return ::SetWindowPos(m_hWnd, nullptr, xLeft, yTop, -1, -1,
			SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}

*/